/*------------------------------------------------------------------------
//                          Project CommonLib                           //
------------------------------------------------------------------------*/

#include "stdafx.h"
#include "CmMiniDumper.h"

#include "Exception.h"

#pragma warning(disable:4995)
namespace Exception 
{
	LPCWSTR MiniDumper::m_szAppName;
	MiniDumper::MiniDumper( LPCWSTR szAppName )
	{
		::SetErrorMode( SEM_FAILCRITICALERRORS );
		m_szAppName = szAppName;
		::SetUnhandledExceptionFilter( TopLevelFilter );
	}

	MiniDumper::~MiniDumper()
	{		
	}

	LONG MiniDumper::TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo )
	{
		LONG retval = EXCEPTION_CONTINUE_SEARCH;
		//HWND hParent = NULL;      // find a better value for your app

		// firstly see if dbghelp.dll is around and has the function we need
		// look next to the EXE first, as the one in System32 might be old 
		// (e.g. Windows 2000)
		HMODULE hDll = NULL;
		WCHAR szDbgHelpPath[_MAX_PATH]={0,};

		if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
		{			
			WCHAR *pSlash = wcsrchr( szDbgHelpPath, '\\' );

			if (pSlash)
			{
				::StringCchCopyW( pSlash+1, _MAX_PATH, L"DBGHELP.DLL" );
				hDll = ::LoadLibrary( szDbgHelpPath );
			}
		}

		if (hDll==NULL)
		{
			// load any version we can
			hDll = ::LoadLibrary( L"DBGHELP.DLL" );
		}

		LPCTSTR szResult = NULL;

		if (hDll)
		{
			MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
			if (pDump)
			{
				TCHAR szDumpPath[_MAX_PATH];
				WCHAR szScratch [_MAX_PATH];

				SYSTEMTIME systemTime;
				::GetLocalTime( &systemTime );
				_snwprintf_s( szDumpPath, _MAX_PATH, TEXT("MINIDUMP_%d-%d-%d__%d_%d_%d.dmp"),
					systemTime.wYear,
					systemTime.wMonth,
					systemTime.wDay,
					systemTime.wHour,
					systemTime.wMinute,
					systemTime.wSecond
					);				

				// ask the user if they want to save a dump file
				if (::MessageBox( NULL, L"Something bad happened in your program, would you like to save a diagnostic file?", m_szAppName, MB_YESNO )==IDYES)
				{
					// create the file
					HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
						FILE_ATTRIBUTE_NORMAL, NULL );

					if (hFile!=INVALID_HANDLE_VALUE)
					{
						_MINIDUMP_EXCEPTION_INFORMATION ExInfo;

						ExInfo.ThreadId = ::GetCurrentThreadId();
						ExInfo.ExceptionPointers = pExceptionInfo;
						ExInfo.ClientPointers = NULL;

						// write the dump
						BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
						if (bOK)
						{
							wsprintf( szScratch, L"Saved dump file to '%s'", szDumpPath );
							szResult = szScratch;
							retval = EXCEPTION_EXECUTE_HANDLER;
						}
						else
						{
							wsprintf( szScratch, L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
							szResult = szScratch;
						}
						::CloseHandle(hFile);
					}
					else
					{
						wsprintf( szScratch, L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
						szResult = szScratch;
					}
				}
			}
			else
			{
				szResult = L"DBGHELP.DLL too old";
			}
		}
		else
		{
			szResult = L"DBGHELP.DLL not found";
		}

		if (szResult)
			::MessageBox( NULL, szResult, m_szAppName, MB_OK|MB_TOPMOST );

		//SEH::ThreadDumper dmp;
		//dmp.Dump(pExceptionInfo);

		return retval;
	}

}
#pragma warning(default:4995)
/*------------------------------------------------------------------------

------------------------------------------------------------------------*/
